#pragma once

#include "RenderHandle.h"
#include "RenderEnums.h"

namespace SL
{

struct ShaderHandle
{};

struct TextureDesc
{
    uint64 alignment;
    uint64 width;
    uint32 height;
    uint16 depthOrArraySize;
    uint16 mipLevels;
    ResourceFormat format;
    uint16 sampleCount;
    // D3D12_TEXTURE_LAYOUT Layout;
    ResourceFlag flags;
    std::string debugName;
};

struct BufferDesc
{
    uint64 alignment;
    uint64 length;
    ResourceFormat format;
    ResourceFlag flags;
};

struct DepthStencilOpDesc
{
    StencilOp failOp;
    StencilOp depthFailOp;
    StencilOp passOp;
    ComparisonFunc compareFunc;
};

struct DepthStencilDesc
{
    bool depthTestEnable;
    bool depthWriteEnable;
    ComparisonFunc depthFunc;
    bool stencilTestEnable;
    uint8 stencilReadMask;
    uint8 stencilWriteMask;
    DepthStencilOpDesc front;
    DepthStencilOpDesc back;
    bool depthBoundsTestEnable;
};

struct RenderTargetBlendDesc
{
    bool blendEnable;
    BlendMode srcBlend;
    BlendMode destBlend;
    BlendOp blendOp;
    BlendMode srcBlendAlpha;
    BlendMode destBlendAlpha;
    BlendOp blendAlphaOp;
    bool logicOpEnable;
    LogicOp logicOp;
    uint8 colorWriteMask;
};

struct BlendDesc
{
    bool alphaToCoverageEnable;
    bool independentBlendEnable;
    RenderTargetBlendDesc renderTarget[8];
};

struct RasterizerDesc
{
    FillMode fillMode;
    CullMode cullMode;
    bool frontCounterClockwise;
    int depthBias;
    float depthBiasClamp;
    float slopeScaledDepthBias;
    bool depthClipEnable;
    bool multisampleEnable;
    bool antialiasedLineEnable;
    uint32 forcedSampleCount;
    bool conservativeRaster;
};

struct GraphicsPipeline
{
    // shader resource bindings
    // ID3D12RootSignature* pRootSignature;
    // mesh format
    // D3D12_INPUT_LAYOUT_DESC InputLayout;
    ShaderHandle VS;
    ShaderHandle PS;
    ShaderHandle DS;
    ShaderHandle HS;
    ShaderHandle GS;
    // D3D12_STREAM_OUTPUT_DESC StreamOutput;
    BlendDesc blendState;
    // uint32 SampleMask = UINT_MAX;
    RasterizerDesc rasterizerState;
    DepthStencilDesc depthStencilState;
    // D3D12_INDEX_BUFFER_STRIP_CUT_VALUE IBStripCutValue;
    PrimitiveTopologyType primitiveTopologyType;
    std::vector<RenderHandle> rtvs;
    RenderHandle dsv;
    uint32 sampleCount = 1;
    uint32 sampleQuality = 0;
    // pipeline state flags

    static GraphicsPipeline OpaquePSO()
    {
        GraphicsPipeline pso;
        BlendDesc blendState = {
            .alphaToCoverageEnable = false,
            .independentBlendEnable = false,
        };
        blendState.renderTarget[0] = RenderTargetBlendDesc{.blendEnable = false, .logicOpEnable = false};
        RasterizerDesc rasterDesc = {
            .fillMode = FillMode::SOLID, .cullMode = CullMode::BACK, .frontCounterClockwise = true, .depthClipEnable = true
        };
        DepthStencilDesc depthStencilDesc = {.depthTestEnable = true, .depthFunc = ComparisonFunc::LESS};
        pso.blendState = blendState;
        pso.rasterizerState = rasterDesc;
        pso.depthStencilState = depthStencilDesc;
        pso.primitiveTopologyType = PrimitiveTopologyType::TRIANGLE;
        pso.sampleCount = 1;
        pso.sampleQuality = 0;
        return pso;
    }
};

struct ComputePipeline
{
    // shader resource bindings
    // ID3D12RootSignature* pRootSignature;
    ShaderHandle CS;
    bool debug;
    // pipeline state flags
};

struct RayTracingPipeline
{
    uint8 recursionDepth;
};

struct MeshShaderPipeline
{
    // ID3D12RootSignature*          pRootSignature;
    ShaderHandle AS;
    ShaderHandle MS;
    ShaderHandle PS;
    // uint32 SampleMask = UINT_MAX;
    BlendDesc BlendState;
    RasterizerDesc RasterizerState;
    DepthStencilDesc DepthStencilState;
    // D3D12_INDEX_BUFFER_STRIP_CUT_VALUE IBStripCutValue;
    PrimitiveTopologyType PrimitiveTopologyType;
    std::vector<RenderHandle> rtvs;
    RenderHandle dsv;
    uint32 sampleCount = 1;
    uint32 sampleQuality = 0;
    // pipeline state flags
};

} // namespace SL